Ext.ns('AIR2.UI');
/***************
 * AIR2 Panel Component
 *
 * Panel styled to capture that sleek AIR2 look, and enable easy definitions
 * of dataviews, edit windows, and edit-in-place panels
 *
 * @class AIR2.UI.Panel
 * @extends Ext.Container
 * @xtype air2panel
 * @cfg {Integer} colspan
 * @cfg {Integer} rowspan
 * @cfg {String} title
 * @cfg {String} iconCls
 * @cfg {Boolean} noHeader (default false)
 * @cfg {Boolean} collapsible (default false)
 * @cfg {Boolean} collapsed (default false)
 * @cfg {Array} tools
 *   Defines the tools positioned in the upper-right of the panel. Accepts
 *   Ext.Toolbar items, including spacers ' ' and alignment '->'.
 * @cfg {Array/Ext.Toolbar} fbar
 *   Defines a toolbar at the bottom of the panel.
 * @cfg {Ext.Template} tpl
 *   Template to render to the body of the panel, as a DataView.
 * @cfg {String} itemSelector
 *   A css selector to use with the tpl
 * @cfg {Boolean} showTotal
 *   Show the total number of items in the tpl
 * @cfg {Object/Array} storeData
 *   Initial data to load tpl store with, rather than an Ajax load
 * @cfg {String} url
 *   Restful url for the store tpl to use
 * @cfg {Boolean} allowEdit
 *   Pass 'false' to hide editInPlace button.  Defaults to true.
 * @cfg {Array} editInPlace
 *   Array of form items to configure an Ext.FormPanel for in-place editing
 * @cfg {Object} editModal
 *   Configuration options to create an Ext.UI.Window when panel is maximized
 * @event beforeedit(formpanel, records)
 * @event validate(formpanel)
 * @event beforesave(formpanel, records)
 * @event aftersave(formpanel, records)
 * @event afteredit(formpanel, records)
 *
 */
AIR2.UI.Panel = function(config) {
    // combine classes, if any were passed in
    var myCls = this.cls;
    if (config.cls) {
        myCls += ' ' + config.cls;
    }
    if (config.editModal) {
        var emCls = myCls;
        if (config.editModal.cls) emCls = emCls + ' ' + config.editModal.cls;
        config.editModal.cls = emCls;
    }
    if (config.collapsed) {
        config.collapsible = true;
        myCls += ' ' + 'air2-panel-collapsed';
    }
    if (config.collapsible) {
        myCls += ' ' + 'air2-panel-collapsible';
    }
    config.cls = myCls;

    // create header tools
    var htools = (config.tools) ? [].concat(config.tools) : [];
    if (config.editInPlace || config.editModal) {
        // search for the right-align in tools
        var al = false;
        for (var i=0; i<htools.length; i++) if (htools[i] == '->') al = true;
        if (!al) htools.push('->');

        // push the edit/maximize tool
        var hide = config.editInPlace && (config.allowEdit == false);
        htools.push(' ', {
            xtype: 'air2button',
            air2type: 'CLEAR',
            iconCls: (config.editInPlace) ? 'air2-icon-edit' : 'air2-icon-modal',
            tooltip: (config.editInPlace) ? 'Edit' : 'Maximize',
            hidden: hide,
            handler: function() {
                if (this.editInPlace) this.startEditInPlace();
                else if (this.editModal) this.startEditModal();
            },
            scope: this
        });
    }

    // create header, unless we do not want one
    if (config.noHeader) {
        this.header = new Ext.BoxComponent({
            cls: 'air2-panel-header',
            hidden: true
        });
    }
    else {
        this.header = new Ext.BoxComponent({
            cls: 'air2-panel-header',
            html:
                '<table class="header-table"><tr>' +
                  '<td class="header-title '+(config.iconCls ? 'icon '+config.iconCls : '') +
                    '">'+(config.title ? config.title : ' ')+'</td>' +
                  '<td class="header-total"></td>' +
                  '<td class="header-tools"> </td>' +
                '</tr></table>',
            listeners: {
                afterrender: function(box) {
                    box.afterrendered = true;
                    this.ownerCt.tools = new Ext.Toolbar({
                        items: htools,
                        renderTo: box.el.child('.header-tools')
                    });

                    // click listener for collapsed header
                    if (config.collapsible) {
                        var pnl = box.ownerCt;
                        box.el.on('click', function(ev) {
                            if (!ev.getTarget('a')) {
                                if (pnl.collapsed) {
                                    pnl.body.el.slideIn('t',{useDisplay:true});
                                    pnl.collapsed = false;
                                    pnl.removeClass('air2-panel-collapsed');
                                }
                                else {
                                    pnl.body.el.slideOut('t',{useDisplay:true});
                                    pnl.collapsed = true;
                                    pnl.addClass('air2-panel-collapsed');
                                }
                            }
                        });
                    }
                }
            },
            setTotal: function(total, unauthz_total) {
                if (this.afterrendered) {
                    var str = Ext.util.Format.number(total, '0,000') + ' Total';
                    var all = this.ownerCt.showAllLink;
                    if (all) str = '<a href="'+all+'">'+str+'&nbsp;&#187;</a>';
                    if (Ext.isDefined(unauthz_total)) {
                        str += ' (' + Ext.util.Format.number(unauthz_total, '0,000') + ' including those you may not view)';
                    }
                    this.el.child('.header-total').update(str);
                }
                else {
                    this.on('afterrender', function() {this.setTotal(total, unauthz_total)}, this);
                }
            }
        });
    }

    // create editform
    this.editform = new Ext.BoxComponent({cls: 'air2-panel-editform'});

    // create body
    this.body = new Ext.Container({cls: 'air2-panel-body'});
    if (config.html) {
        this.body.add({xtype: 'box', html: config.html});
        delete config.html;
    }
    if (config.tpl) {
        this.body.add({
            xtype: 'air2jsdv',
            cls: 'air2-panel-dataview',
            url: config.url,
            data: config.storeData,
            tpl: config.tpl,
            itemSelector: config.itemSelector,
            emptyText: config.emptyText,
            deferEmptyText: config.deferEmptyText,
            listeners: {
                load: function(store) {
                    if (config.showTotal) this.setTotal(store.getTotalCount());
                    this.store = store; // cache reference to store
                },
                scope: this
            }
        });
        delete config.url;
        delete config.tpl;
    }
    if (config.items) {
        this.body.add(config.items);
        delete config.items;
    }

    // create footer (optional)
    if (config.fbar) {
        if (config.fbar.isXType && config.fbar.isXType('toolbar')) {
            config.fbar.addClass('air2-panel-footer');
            this.footer = config.fbar;
        }
        else {
            this.footer = new Ext.Toolbar({
                cls: 'air2-panel-footer',
                items: config.fbar
            });
        }
    }

    // call parent constructor
    config.items = [this.header, this.editform, this.body];
    if (this.footer) config.items.push(this.footer);
    AIR2.UI.Panel.superclass.constructor.call(this, config);

    // add custom events
    this.addEvents('beforeedit');
    this.addEvents('afteredit');
    this.addEvents('beforesave');
    this.addEvents('aftersave');
    this.addEvents('validate');
}
Ext.extend(AIR2.UI.Panel, Ext.Container, {
    cls: 'air2-panel',
    startEditModal: function() {
        // create the window, if it doesn't exist yet
        if (!this.editModal.show) {
            if (!this.editModal.iconCls) this.editModal.iconCls = this.iconCls;
            if (!this.editModal.title) this.editModal.title = this.title;
            this.editModal = new AIR2.UI.Window(this.editModal);
            this.editModal.on('hide', function() {
                this.reload(); //get any changes from modal editing
            }, this);
        }
        this.editModal.show(this.el);
    },
    startEditInPlace: function() {
        // if we're already editing, cancel the edit!
        if (this.isediting) return this.endEditInPlace(false);

        // create edit panel, if we haven't already
        if (!this.editInPlacePanel) {
            this.editInPlace.push({
                xtype: 'toolbar',
                style: 'background:none;border:0;',
                items: [{
                    xtype: 'air2button',
                    air2type: 'SAVE',
                    air2size: 'MEDIUM',
                    text: 'Save',
                    scope: this,
                    handler: function() {this.endEditInPlace(true)}
                },{
                    xtype: 'air2button',
                    air2type: 'CANCEL',
                    air2size: 'MEDIUM',
                    text: 'Cancel',
                    style: 'margin-left:4px',
                    scope: this,
                    handler: function() {this.endEditInPlace(false)}
                }]
            });
            this.editInPlacePanel = new Ext.form.FormPanel({
                cls: 'air2-panel-editinplace air2-panel-body',
                items: this.editInPlace,
                unstyled: true,
                hidden: true,
                labelWidth: 75,
                defaults: {style: {width: '96%'}},
                applyTo: this.getEditForm().el
            });
        }
        this.isediting = true;

        // get EVERY record in EVERY dataview
        var b = this.getBody(), r = [];
        b.items.each(function(item, index, length) {
            if (item.store) {
                if (item.store.getCount() == 0)
                    item.store.add(new item.store.recordType());
                r = r.concat(item.store.getRange());
            }
        });
        this.inPlaceRecs = r;

        // reset the panel
        var p = this.editInPlacePanel;
        p.getForm().reset();
        if (r.length == 1) p.getForm().loadRecord(r[0]);

        // fire beforeedit, and show the form (hiding the dataviews)
        if (this.fireEvent('beforeedit', p, r)) {
            b.hide();
            p.show();
            p.getForm().isValid();
            p.getForm().items.get(0).focus(true); //focus first field
        }
    },
    endEditInPlace: function(doSave) {
        var p = this.editInPlacePanel, r = this.inPlaceRecs, stores = [];
        if (doSave) {
            // default and custom form validation
            if (!p.getForm().isValid()) return;
            if (!this.fireEvent('validate', p)) return;

            // create a list of every distinct store
            for (i=0; i<r.length; i++) {
                if (r[i].store && stores.indexOf(r[i].store) < 0)
                    stores.push(r[i].store);
            }

            // begin editing recs
            for (var i=0; i<r.length; i++) r[i].beginEdit();

            // update record
            if (r.length == 1) p.getForm().updateRecord(r[0]);
            this.fireEvent('beforesave', p, r);

            // end editing record
            for (i=0; i<r.length; i++) r[i].endEdit();

            // find any stores that were added during 'beforesave'
            for (i=0; i<r.length; i++) {
                if (r[i].store && stores.indexOf(r[i].store) < 0)
                    stores.push(r[i].store);
            }

            // save any recs that have been modified
            var reqs = [], pan = this;
            for (i=0; i<stores.length; i++) {
                // set the callback
                stores[i].on('save', function(store, batch) {
                    reqs.remove(batch);
                    if (reqs.length < 1) {
                        if (pan.fireEvent('aftersave', p, r)) {
                            p.el.unmask();
                            pan.endEditInPlace(false);
                        }
                    }
                }, this, {single: true});

                // save, and record the save batch number
                var n = stores[i].save();
                if (n > 0) reqs.push(n);
            }

            // check if we fired any save events
            if (reqs.length > 0) {
                p.el.mask('Saving...');
                return; // avoid exiting until callback
            }
            else {
                this.endEditInPlace(false); // end edit NOW
            }
        }
        else {
            // process after-edit
            if (this.fireEvent('afteredit', p, r)) {
                this.isediting = false;
                p.hide();
                this.getBody().show();
            }

            // prune cancelled new-recs
            Ext.each(r, function(rec) {
                if (rec.phantom && rec.store) rec.store.remove(rec);
            });
        }
    },
    setTotal: function(total, unauthz_total) {
        this.header.setTotal(total, unauthz_total);
    },
    reload: function() {
        this.getBody().items.each(function(item) {
            if (item.store && item.store.proxy) item.store.reload();
        });
    },
    // getters for the panel components
    getHeader: function() {
        return this.header;
    },
    getTools: function() {
        return this.tools;
    },
    getEditForm: function() {
        return this.editform;
    },
    getBody: function() {
        return this.body;
    },
    getFooter: function() {
        return this.footer;
    }
});
Ext.reg('air2panel', AIR2.UI.Panel);
